Improve explicit histogram contention performance - #8717
Conversation
Pull request dashboard statusMerged · refreshed 2026-09-10 22:29 UTC Status above doesn't look right?
|
| @ParameterizedTest | ||
| @MethodSource("stressTestArgs") | ||
| @Timeout(value = 10, unit = TimeUnit.SECONDS, threadMode = Timeout.ThreadMode.SEPARATE_THREAD) | ||
| void partialWriteStressTest( |
There was a problem hiding this comment.
This new test checks that the intermediate state of every collect is correct and doesn't include partial writes. Asserting this was particularly important with the complex lock free implementations I experimented with. The current test asserts that the aggregate state after a bunch of records and collects is correct, which ensures no lost writes or double writes.
But we had no tests asserting no partial writes, and with a lock based implementation it was easier to ignore this lack of coverage.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #8717 +/- ##
============================================
- Coverage 91.29% 91.26% -0.03%
- Complexity 10498 10502 +4
============================================
Files 1006 1007 +1
Lines 28338 28403 +65
Branches 3581 3605 +24
============================================
+ Hits 25870 25923 +53
- Misses 1675 1683 +8
- Partials 793 797 +4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…y-java into lock-free-explicit-histogram-clean
|
FYI, @open-telemetry/java-approvers I plan on merging this tomorrow 9/10 (ahead of Friday's 1.66.0 release) unless there are any dissenting opinions or folks that intend to review but haven't had the chance yet |
…cenarios (#2451) Updating benchmarks after substantial efforts to improve otel performance under contention. Changes: - Add scenarios for experimental bound instruments. I understand if you want to reject this until stable. - Disable exemplars for apples to apples comparison. My understanding is that the prom client_java cases don't have exemplars enabled, can change if I'm wrong. - Update to opentelemetry-java v1.66.0. If we wait until opentelemetry-java-instrumentation version is released which bundles the v1.66.0 version, the clutter in pom.xml goes away. Benchmark results on my machine: ``` Benchmark Mode Cnt Score Error Units CounterBenchmark.codahaleIncNoLabels thrpt 25 95236.680 ± 755.718 ops/s CounterBenchmark.openTelemetryAdd thrpt 25 54598.238 ± 290.633 ops/s CounterBenchmark.openTelemetryBoundAdd thrpt 25 82770.849 ± 342.576 ops/s CounterBenchmark.openTelemetryBoundInc thrpt 25 85165.317 ± 7.693 ops/s CounterBenchmark.openTelemetryInc thrpt 25 75136.160 ± 552.123 ops/s CounterBenchmark.openTelemetryIncNoLabels thrpt 25 85517.108 ± 538.105 ops/s CounterBenchmark.prometheusAdd thrpt 25 84533.092 ± 680.646 ops/s CounterBenchmark.prometheusInc thrpt 25 85135.753 ± 23.184 ops/s CounterBenchmark.prometheusNoLabelsInc thrpt 25 85061.556 ± 194.011 ops/s CounterBenchmark.simpleclientAdd thrpt 25 9174.173 ± 1542.709 ops/s CounterBenchmark.simpleclientInc thrpt 25 8860.946 ± 1306.154 ops/s CounterBenchmark.simpleclientNoLabelsInc thrpt 25 17502.624 ± 830.879 ops/s HistogramBenchmark.openTelemetryBoundClassic thrpt 25 25261.802 ± 6559.742 ops/s HistogramBenchmark.openTelemetryBoundExponential thrpt 25 2367.637 ± 381.165 ops/s HistogramBenchmark.openTelemetryClassic thrpt 25 28697.261 ± 4082.434 ops/s HistogramBenchmark.openTelemetryExponential thrpt 25 1868.494 ± 101.732 ops/s HistogramBenchmark.prometheusClassic thrpt 25 23600.746 ± 7292.571 ops/s HistogramBenchmark.prometheusClassicPerThread thrpt 25 58674.695 ± 98.620 ops/s HistogramBenchmark.prometheusClassicSingleThread thrpt 25 14865.898 ± 12.295 ops/s HistogramBenchmark.prometheusNative thrpt 25 10726.819 ± 677.244 ops/s HistogramBenchmark.simpleclient thrpt 25 17340.988 ± 266.176 ops/s ``` The [improvements](open-telemetry/opentelemetry-java#8717) to otel explicit histogram performance came from a design inspired by prometheus client_java. The code contains attribution. I did manage to slightly improve on the design - If you agree, I'm happy to chat about it and encourage prom client_java to copy any of the bits you think are helpful. --------- Signed-off-by: Jack Berg <34418638+jack-berg@users.noreply.github.com>
My goal is to have OpenTelemetry metrics equal or exceed performance of other metrics systems, in an apples-to-apples comparison.
In this PR, I address the poor performance of explicit histograms under contention, as embodied by this prometheus/client_java benchmark.
I have issues with this benchmark. The real performance characteristic is more nuanced than can be captured by recording to a single bound series. To get the complete picture, I extended MetricRecordBenchmark to add a
prometheus=false|trueparameter, allowing comparison against prometheus alongside the parameters we've deemed valuable.But there's no denying it: otel java's current simple lock based approach (predictably) gets steamrolled by a lock free design under contention.
The problem with fixing this is that lock based approach performs maximally well without contention. I've been thinking / iterating on designs on and off for months and there is no change I've found or am aware of that improves contended performance without regressing uncontended performance. This has been a sticking point in the past. So the approach I've taken with this PR:
prometheus/client_java, with modifications to avoid the complexity of having a buffer and to also optionally record min and max.Context.current()when exemplars are disabled is unnecessary and represents a significant chunk of work (at least on a relative basis).So how do we compare to prometheus/client_java? There are a lot of params that make it a bit overwhelming to interpret the data. Many of the param combinations tell variations of the same overall story. I've compressed the story into one graph which I think is fair and understandable. Notes:
Below is a before and after of the unmodified
MetricRecordBenchmark. This shows clearly shows the contended gains and uncontended regressions.Details
Takeaways from a performance standpoint: